import os
import re
import json

from datetime import datetime, timedelta
from datetime import time as dtime
import time
import sys
from stat import S_ISDIR

from queue import Queue
import shutil

import threading
from tika import parser
from server.report.utils.mysql_utils import mysql_util 
from server.config.log import logger
from server.report.config.config import Config
from server.report.models.model import Report
from server.report.job.scene import SceneManager
from server.report.job.chat import DeepSeekInternalClient
from server.report.job.doc_processor import WordDocumentProcessor
from .email_job import EmailReport


class ReportJob(object):
    def __init__(self):
        self.stop = threading.Event()
        # 是否是拷贝当天的数据

        self.root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

        # 存放上传的 doc 文件路径
        self.doc_queue = Queue()

        # 当前正在处理的任务
        self.deal_job_code = None

        self.ai_client = DeepSeekInternalClient()
        self.doc_processor = WordDocumentProcessor()
        self.email_report = EmailReport()
    

    def extract_file_content(self, file_path):
        # 解析文件内容
        raw = parser.from_file(file_path)

        # 提取内容和元数据
        content = raw['content']        # 提取的文本内容（保留段落、换行等结构）
        metadata = raw['metadata']      # 提取的元数据（如作者、标题等）
        status = raw['status']          # 请求状态码（200 表示成功）

        return {
            'content': content.strip(),  # 提取的文本内容
            'metadata': metadata,        # 元数据信息
            'status': status
        }


    # 启动 serverv 服务的同时,启动推理后台任务
    def start(self):

        logger.info("启动推理后台任务")
        
        while not self.stop.is_set():

            try:
                # 当没有处理拷贝任务时,取出新的任务
                report_id = self.doc_queue.get(timeout=1)
            except Exception as e:
                time.sleep(1)
                continue

            logger.info(f"取到 report id: {report_id}")

            with mysql_util.get_db() as db:

                report = db.query(Report).filter_by(id=report_id).first()

                # 取消的任务不处理
                if report.status == "CANCELLED":
                    continue

                report.status = "DOING"
                db.commit()

                try:
                    input_file_path = report.input_file_path
                    scene = report.scene
                    report_name = report.report_name

                    logger.info("步骤1: 开始解析客户数据")
                    doc_content = self.extract_file_content(input_file_path)['content']

                    # 2. 使用AI生成器生成所有内容
                    logger.info("步骤2: 开始生成各段落内容")
                    generated_content = self.generate_all_sections(doc_content, scene)

                    # 3. 使用文档处理器将生成的内容保存到 Word 文档
                    logger.info("步骤3: 开始保存成Word文档")
                    output_path = self.doc_processor.process_document(generated_content, scene)

                    report.status = "DONE"
                    report.generate_date = datetime.now()
                    report.output_file_path = output_path

                    db.commit()

                    # 发送成功邮件通知
                    self.email_report.sent_ok_email(report.id)

                except Exception as e:
                    report.status = "FAILED"

                    db.commit()

                    logger.error(f"生成报错出错，错误信息：{e}")

                    error_msg = str(e) if e else "无报错信息"

                     # 发送错误邮件通知
                    self.email_report.sent_error_email(error_msg, report.id)

            # 控制频率
            time.sleep(0.1)

            
    def add_doc(self, report_id):
        self.doc_queue.put(report_id)


    def _build_prompt(self, prompt: dict, customer_data: str, generated_content: dict) -> str:
        """根据配置动态构建和格式化提示词"""
        prompt_str = "\n".join(prompt["prompt"])
        logger.info(f"原始提示词长度: {len(prompt_str)} 字符")
        
        # 根据input_type动态构建提示词参数
        format_params = {}
        if "input_type" in prompt:
            input_types = prompt["input_type"]
            logger.info(f"处理输入类型: {input_types}")
            
            for input_type in input_types:
                if input_type == "creditor_info":
                    format_params[input_type] = str(customer_data)
                    logger.debug(f"添加客户数据参数: {input_type}")
                else:
                    if input_type in generated_content:
                        format_params[input_type] = generated_content[input_type]
                        logger.debug(f"添加已生成内容参数: {input_type}")
                    else:
                        logger.warning(f"未找到已生成内容: {input_type}，使用空字符串")
                        format_params[input_type] = ""
        else:
            # 兼容旧版本
            logger.info("未找到input_type配置，使用默认方式")
            format_params["creditor_info"] = str(customer_data)
        
        # 格式化提示词
        try:
            if format_params:
                prompt = prompt_str.format(**format_params)
            else:
                prompt = prompt_str + "\n\n" + str(customer_data)
            logger.info(f"格式化后提示词长度: {len(prompt)} 字符")
        except KeyError as e:
            logger.error(f"提示词格式化失败，缺少参数: {e}")
            prompt = prompt_str + "\n\n" + str(customer_data)
            logger.info("使用默认方式构建提示词")
        
        return prompt


    def _generate_section_content(self, scene_manager: SceneManager, section_template: dict, customer_data: str, generated_content: dict) -> dict:
        """为特定段落生成内容"""
        section_name = section_template.get('section_name', section_template.get('section_id', 'Unknown'))
        logger.info(f"开始生成段落内容: {section_name}")
        
        try:
            prompt_key = section_template["prompt_key"]
            
            prompt_template = scene_manager.get_prompt(prompt_key)
            if not prompt_template:
                logger.error(f"未找到提示词配置: {prompt_key}")
                raise ValueError(f"未找到提示词配置: {prompt_key}")
            
            # 构建提示词
            prompt = self._build_prompt(prompt_template, customer_data, generated_content)
            
            # 根据use_common_search_agent决定是否启用搜索
            enable_search = prompt_template.get("use_common_search_agent", False)
            logger.info(f"启用搜索功能: {enable_search}")
            
            # 调用AI生成内容
            logger.info("开始调用AI生成内容")
            response = self.ai_client.chat_with_search(prompt, enable_search=enable_search)
            logger.info("调用AI生成内容结束")
            
            if response and "content" in response:
                content = response["content"]
                logger.info(f"AI内容生成成功，长度: {len(content)} 字符")
                
                # 如果有推理内容，也记录到日志
                if "reasoning_content" in response and response["reasoning_content"]:
                    logger.debug(f"AI推理过程长度: {len(response['reasoning_content'])} 字符")
                
                # 根据output_type处理内容
                return self._process_ai_response(content, prompt_template, section_template)
            else:
                logger.error("AI响应格式错误或为空")
                raise ValueError("AI响应格式错误或为空")
                
        except Exception as e:
            logger.error(f"段落内容生成失败 ({section_name}): {e}")
            raise

    def generate_all_sections(self, customer_data: str, scene) -> dict:
        """生成所有段落内容"""
        logger.info("开始生成所有段落内容")
        generated_content = {}

        # 获取模板数据
        scene_manager = SceneManager(scene)

        sections = scene_manager.template["template_sections"]

        logger.info(f"共需要生成 {len(sections)} 个段落")
        
        for i, section in enumerate(sections, 1):
            logger.info(f"正在生成第 {i}/{len(sections)} 个段落: {section.get('section_name', section.get('section_id', 'Unknown'))}")
            try:
                content = self._generate_section_content(scene_manager, section, customer_data, generated_content)
                
                # 处理placeholder列表
                placeholders = section["placeholder"]
                if isinstance(placeholders, list):
                    for placeholder in placeholders:
                        if placeholder in content:
                            generated_content[placeholder] = content[placeholder]
                            logger.debug(f"添加占位符内容: {placeholder}")
                        else:
                            logger.warning(f"在生成内容中未找到占位符: {placeholder}")
                else:
                    generated_content[placeholders] = content[placeholders]
                    logger.debug(f"添加占位符内容（非列表）: {placeholders}")
                
                logger.info(f"段落 {i} 生成成功，内容长度: {len(str(content))} 字符")
            except Exception as e:
                logger.error(f"段落 {i} 生成失败: {e}")
                raise
        
        logger.info(f"所有段落内容生成完成，共生成 {len(generated_content)} 个占位符内容")
        return generated_content



    def _process_ai_response(self, content: str, prompt: dict, section: dict) -> dict:
        """处理AI响应内容"""
        output_type = prompt.get("output_type", "MARKDOWN")
        logger.debug(f"输出类型: {output_type}")
        
        if output_type == "MARKDOWN":
            # MARKDOWN类型：封装成字典
            processed_content = {"{{" + section["prompt_key"] + "}}": content}
            logger.debug(f"MARKDOWN格式处理完成，键: {section['prompt_key']}")
        elif output_type == "JSON":
            # JSON类型：剔除代码块标记并转换为字典
            cleaned_content = re.sub(r'^```json\s*', '', content, flags=re.MULTILINE)
            cleaned_content = re.sub(r'\s*```$', '', cleaned_content, flags=re.MULTILINE)
            cleaned_content = cleaned_content.strip()
            
            try:
                processed_content = json.loads(cleaned_content)
                logger.debug(f"JSON格式处理完成，解析出 {len(processed_content)} 个键")
                
                # 为每个key前后添加双花括号
                formatted_content = {}
                for key, value in processed_content.items():
                    formatted_key = "{{" + key + "}}"
                    formatted_content[formatted_key] = value
                    logger.debug(f"格式化键: {key} -> {formatted_key}")
                
                processed_content = formatted_content
                logger.debug(f"键格式化完成，共处理 {len(processed_content)} 个键")
                
            except json.JSONDecodeError as e:
                logger.error(f"JSON解析失败: {e}，使用原始内容")
                processed_content = {"{{" + section["prompt_key"] + "}}": content}
        else:
            # 其他类型：使用默认处理方式
            processed_content = {"{{" + section["prompt_key"] + "}}": content}
            logger.warning(f"未知输出类型: {output_type}，使用默认处理方式")
        
        return processed_content
    
        
    
report_job = ReportJob()